
/**
 * <p>Title: loginSvcImpl</p>
 * <p>Description: loginSvc接口的实现类</p>
 * <p>Copyright: Shanghai Batchsight Pharmaceutical Technologies, Inc. Copyright(c) 2016</p>
 * @author Qian Pengji
 * @version 1.0
 * <pre>Histroy:
 *       2016-9-29  Qian Pengji  Create
 *</pre>
*/
package cn.jhg.account.service;

import java.security.NoSuchAlgorithmException;
import java.sql.Timestamp;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.Resource;
import org.apache.commons.collections.bidimap.DualHashBidiMap;
import org.bson.Document;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import cn.jhg.account.entity.AuditTrailObject;
import cn.jhg.account.entity.AuditTrailRecord;
import cn.jhg.account.entity.AuditTrailType;
import cn.jhg.account.entity.User;
import cn.jhg.account.persist.UserDao;
import cn.jhg.account.service.AuditTrailSvc;
import cn.jhg.account.util.SHAUtil;
import cn.jhg.account.util.ServiceResult;

@Service("loginSvc")
@Transactional
public class LoginSvcImpl implements LoginSvc {

	@Resource
	private UserDao userDao;
	// 双向map,key值为验证码，value值为用户id
	DualHashBidiMap dualHashBidiMap = new DualHashBidiMap();
	Logger logger = LoggerFactory.getLogger(LoginSvcImpl.class);
	@Resource
	private AuditTrailSvc auditTrailSvc;

	/**
	 * <p>Function: login 用户登录操作</p>
	 * <p>Description: 验证传入的账号与密码是否存在，验证账号状态是否可用， 验证用户密码有效期,
	 * 登录成功后系统生成一个随机的验证码返回用户，后续操作中使用该验证码进行用户权限验证 调用审计追踪模块，
	 * 记录本次登录信息（包括登录成功及不成功）</p>
	 * @param String account, String password 用户帐号,密码
	 * @return ServiceResult<String> 返回错误代码/验证码（如果登录成功）
	 */
	@Override
	public ServiceResult<User> login(String account, String password) {
		ServiceResult<User> serviceResult = new ServiceResult<User>();

		try {
			Map<String, String> map = new HashMap<String, String>();
			map.put("account", account);
			map.put("password", password);
			User mapLogin = userDao.logIn(map);
			User user = userDao.getUserByAccount(account);
			if (user == null) {
				serviceResult.setErrorCode(219219971);// 用户名不存在
				logger.error("[ERR219219971] 用户名不存在");
				return serviceResult;
			} else if (mapLogin == null) {
				serviceResult.setErrorCode(219220413);// 密码错误
				logger.error("[ERR219220413] 密码错误");
				return serviceResult;
			} else if ((user.getStatus() & 8) != 0 || (user.getStatus() & 16) != 0 || (user.getStatus() & 24) !=0) {
				serviceResult.setErrorCode(219144733);// 锁定、失效状态、锁定失效不能登录
				logger.error("[ERR219144733] 锁定、失效、锁定失效状态不能登录");
				return serviceResult;
			} 

			Date date = new Date();
			date = user.getPwdValidDate();
			Date now = new Date();
			if (now.getTime() > date.getTime()) {
				serviceResult.setErrorCode(219144801);// 验证用户密码有效期超时
				logger.error("[ERR219144801] 验证用户密码有效期超时");
				return serviceResult;
			} 
			serviceResult.setErrorCode(0);
			serviceResult.setData(mapLogin);
			logger.info("[INF219146165] 登录成功");
			return serviceResult;

		} catch (Exception e) {//try 语句结束
			TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
			serviceResult.setErrorCode(219310442);// 帐号密码登录失败
			logger.error("[ERR219310442] 帐号密码登录失败" + e.getMessage());
			return serviceResult;
		}

	}

	/**
	 * <p>Function: logout 用户登出 </p>
	 * @param int uid 用户id
	 * @param int iuid 调用者 id
	 * @return ServiceResult<Object> 返回错误代码
	 */
	@Override
	public ServiceResult<Object> logout(int uid, int iuid) {
		ServiceResult<Object> serviceResult = new ServiceResult<Object>();

		try {
			User user = userDao.getUserById(uid);
			if (user == null) {
				serviceResult.setErrorCode(219220038);// id不存在
				logger.error("[ERR219220038] 此ID的用户不存在");
			} else {
				dualHashBidiMap.removeValue(uid);
				serviceResult.setErrorCode(0);
				logger.info("[INF219146270] 登出成功");
			}
			return serviceResult;
		} catch (Exception e) {
			TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
			serviceResult.setErrorCode(219310545);// 登出失败
			logger.error("[ERR219310545] 登出失败" + e.getMessage());
			return serviceResult;
		}

	}

	/**
	 * <p>Function: changePassword 修改密码</p>
	 * <p>Description:修改数据库中的用户密码，记录审计追踪信息，并在当前日期增加1个月期限</p>
	 * @param int uid, String oldPwd, String newPwd 用户id，旧密码，新密码
	 * @return ServiceResult<Object> 返回错误代码
	 */
	@Override
	public ServiceResult<Object> changePassword(String account, String oldPwd, String newPwd) {
		ServiceResult<Object> serviceResult = new ServiceResult<Object>();

		try {
			User user = userDao.getUserByAccount(account);
			if (user == null) {
				serviceResult.setErrorCode(219220097);// 账号用户不存在
				logger.error("[ERR219220097] 账号用户不存在");
			} else if (oldPwd.equals(user.getPassword())) {
				user.setPassword(newPwd);// 将用户的新密码设置为密码
				long now = System.currentTimeMillis();// 获取当前时间（毫秒）
				long Interval = (long) (30L * 24L * 60L * 60L * 1000L);// 设置期限30天
				long time = now + Interval;// 当前时间增加30天
				Timestamp t = new Timestamp(time);// 转换为时间戳
				user.setPwdValidDate(t);// 设置时间戳
				try {
					userDao.updateUser(user);// 更新用户操作
				} catch (Exception e) {
					serviceResult.setErrorCode(219379691);
					logger.error("[ERR219379691] 更新失败" + e.getMessage());
					return serviceResult;
				}
				serviceResult.setErrorCode(0);// 插入新密码成功
				logger.info("[INF219146309] 修改密码成功");
			}else{
				serviceResult.setErrorCode(220677509);
				logger.error("[ERR220677509] 输入密码错误");
			}
			return serviceResult;
		} catch (Exception e) {//try 语句结束
			TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
			serviceResult.setErrorCode(219310685);// 修改密码失败
			logger.error("[ERR219310685] 修改密码失败" + e.getMessage());
			return serviceResult;
		}

	}

	/**
	 * <p>Function: resetPassword 重置密码</p>
	 * <p>Description:为用户随机生成一个新的密码 密码以 SHA-256 算法加密后存入数据库 将用户密码有效期修改为当前时间,记录审计追踪信息</p>
	 * @param int uid 用户id
	 * @param int sid 签名 id（操作前用户确认签名记录的 id）
	 * @param int iuid 调用者 id
	 * @return ServiceResult<String> 返回错误代码，新密码
	 */
	@Override
	public ServiceResult<String> resetPassword(int uid, int sid,int iuid) {
		ServiceResult<String> serviceResult = new ServiceResult<String>();

		try {
			User user = userDao.getUserById(uid);
			if (user == null) {
				serviceResult.setErrorCode(219220131);// id不存在
				logger.error("[ERR219220131] 此ID的用户不存在");
			} else {
				String s = SHAUtil.getStringRandom(6);// 获取6位随机码
				serviceResult.setData(s);
				try {
					String pwd=SHAUtil.convertByteToHexString(s);
					user.setPassword(pwd);// 设置加密密码			
				} catch (NoSuchAlgorithmException e) {
					serviceResult.setErrorCode(219391510);// 加密失败
					logger.error("[ERR219391510] 加密失败" + e.getMessage());
					return serviceResult;
				}
				long now = System.currentTimeMillis();// 获取当前时间（毫秒）
				Timestamp t = new Timestamp(now);// 转换为时间戳
				user.setPwdValidDate(t);	
				try {
					userDao.updateUser(user);// 更新所有的操作
				} catch (Exception e) {
					serviceResult.setErrorCode(219379829);
					logger.error("[ERR219379829] 更新失败" + e.getMessage());
					return serviceResult;
				}
				serviceResult.setErrorCode(0);
				logger.info("[INF219146727] 重置密码成功");
				
				// 添加审计追踪记录
				AuditTrailRecord atRecord = new AuditTrailRecord();
				atRecord.setSid(sid); // 签名 id
				atRecord.setUid(iuid); // 用户 id
				atRecord.setLid(100);
				atRecord.setTid(AuditTrailType.ResetPassword.GetId()); // 审计追踪类型 id
				atRecord.setOtid(AuditTrailObject.User.getId());    // 审计追踪对象 id

				Document metadata = new Document(); // 审计追踪元数据
				metadata.append("UserId", user.getId());
				metadata.append("Account", user.getAccount());
				metadata.append("UserName",  user.getName());
				atRecord.setMeta(metadata);
				
				auditTrailSvc.addRecord(atRecord);
			}//else  语句结束
			return serviceResult;
		} catch (Exception e) {//try 语句结束
			TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
			serviceResult.setErrorCode(219310803);// 重置密码失败
			logger.error("[ERR219310803] 重置密码失败" + e.getMessage());
			return serviceResult;
		}

	}

	/**
	 * <p>Function: lockAccount 锁定用户</p>
	 * <p>Description:将用户状态置为锁定（按位或）,记录审计追踪信息</p>
	 * @param int uid 用户id
	 * @param int sid 签名 id（操作前用户确认签名记录的 id）
	 * @param int iuid 调用者 id
	 * @return ServiceResult<Object> 返回错误代码
	 */
	@Override
	public ServiceResult<Object> lockAccount(int uid,int sid, int iuid) {
		ServiceResult<Object> serviceResult = new ServiceResult<Object>();
		try {
			User user = userDao.getUserById(uid);		
			if (user == null) {
				serviceResult.setErrorCode(219220214);// id不存在
				logger.error("[ERR219220214] 此ID的用户不存在");
			} else {
				String password=userDao.getPasswordById(uid);
				user.setPassword(password);
				int status = user.getStatus();
				int lock = status | 8;// 按位或操作，8对应00001000，第四位为1
				user.setStatus(lock);
				try {
					userDao.updateUser(user);
				} catch (Exception e) {
					serviceResult.setErrorCode(219379548);
					logger.error("[ERR219379548] 更新失败" + e.getMessage());
					return serviceResult;
				}
				serviceResult.setErrorCode(0);
				serviceResult.setData(lock);
				logger.info("[INF219146570] 锁定成功");
				
				// 添加审计追踪记录
				AuditTrailRecord atRecord = new AuditTrailRecord();
				atRecord.setSid(sid); // 签名 id
				atRecord.setUid(iuid); // 用户 id
				atRecord.setLid(100);
				atRecord.setTid(AuditTrailType.LockAccount.GetId()); // 审计追踪类型 id
				atRecord.setOtid(AuditTrailObject.User.getId());    // 审计追踪对象 id

				Document metadata = new Document(); // 审计追踪元数据
				metadata.append("UserId", user.getId());
				metadata.append("Account", user.getAccount());
				metadata.append("UserName",  user.getName());
				atRecord.setMeta(metadata);
				
				auditTrailSvc.addRecord(atRecord);
			}//else 语句结束
			return serviceResult;
		} catch (Exception e) {//try 语句结束
			TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
			serviceResult.setErrorCode(219310909);// 锁定失败
			logger.error("[ERR219310909] 锁定失败" + e.getMessage());
			return serviceResult;
		}
	}

	/**
	 * <p>Function: unlockAccount 解锁用户</p>
	 * <p>Description:将用户状态置为非锁定(按位与),记录审计追踪信息</p>
	 * @param int uid 用户id
	 * @param int sid 签名 id（操作前用户确认签名记录的 id）
	 * @param int iuid 调用者 id
	 * @return ServiceResult<Object> 返回错误代码
	 */
	@Override
	public ServiceResult<Object> unlockAccount(int uid,int sid, int iuid) {
		ServiceResult<Object> serviceResult = new ServiceResult<Object>();

		try {
			User user = userDao.getUserById(uid);
			if (user == null) {
				serviceResult.setErrorCode(219220239);// id不存在
				logger.error("[ERR219220239] 此ID的用户不存在");
			} else {
				String password=userDao.getPasswordById(uid);
				user.setPassword(password);
				int status = user.getStatus();
				int unlock = status & 7;// 按位与解锁，0111，确保第四位为0
				user.setStatus(unlock);
				try {
					userDao.updateUser(user);
				} catch (Exception e) {
					serviceResult.setErrorCode(219380040);
					logger.error("[ERR219380040] 更新失败" + e.getMessage());
					return serviceResult;
				}
				serviceResult.setErrorCode(0);
				serviceResult.setData(unlock);
				logger.info("[INF219146536] 解锁成功");
				
				// 添加审计追踪记录
				AuditTrailRecord atRecord = new AuditTrailRecord();
				atRecord.setSid(sid); // 签名 id
				atRecord.setUid(iuid); // 用户 id
				atRecord.setLid(100);
				atRecord.setTid(AuditTrailType.UnlockAccount.GetId()); // 审计追踪类型 id
				atRecord.setOtid(AuditTrailObject.User.getId());    // 审计追踪对象 id

				Document metadata = new Document(); // 审计追踪元数据
				metadata.append("UserId", user.getId());
				metadata.append("Account", user.getAccount());
				metadata.append("UserName",  user.getName());
				atRecord.setMeta(metadata);
				
				auditTrailSvc.addRecord(atRecord);
			}//else 语句结束
			return serviceResult;
		} catch (Exception e) {//try 语句结束
			TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
			serviceResult.setErrorCode(219311029);// 解锁失败
			logger.error("[ERR219311029] 解锁失败" + e.getMessage());
			return serviceResult;
		}

	}

	/**
	 * <p>Function: getPwdExpiryDate 获取密码有效期</p>
	 * <p>Description:根据用户id获取密码有效期</p>
	 * @param int uid 用户id
	 * @return ServiceResult<Timestamp> 返回错误代码,有效期
	 */
	@Override
	public ServiceResult<Timestamp> getPwdExpiryDate(int uid) {
		ServiceResult<Timestamp> serviceResult = new ServiceResult<Timestamp>();

		try {
			User user = userDao.getUserById(uid);
			if (user == null) {
				serviceResult.setErrorCode(219220272);// id不存在
				logger.error("[ERR219220272] 此ID的用户不存在");
			} else {
				Timestamp timestamp = user.getPwdValidDate();
				serviceResult.setData(timestamp);
				serviceResult.setErrorCode(0);
				logger.info("[INF219146617] 获取密码有效期成功");
			}
			return serviceResult;

		} catch (Exception e) {
			TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
			serviceResult.setErrorCode(219311087);// 获取密码失败
			logger.error("[ERR219311087] 获取密码失败" + e.getMessage());
			return serviceResult;
		}
	}

	/**
	 * <p>Function: queryAuthenticatedUser 查询当前登录的用户 Id</p>
	 * <p>Description:根据登录验证码查询当前登录用户的 id</p>
	 * @param String auth 验证码
	 * @return ServiceResult<Integer> 返回错误代码，用户id
	 */
	@Override
	public ServiceResult<Integer> queryAuthenticatedUser(String auth) {
		ServiceResult<Integer> serviceResult = new ServiceResult<Integer>();
		
		try {
			if (auth == null || "".equals(auth)) {
				serviceResult.setErrorCode(219201409);// 验证码不存在
				logger.error("[ERR219201409] 验证码不存在");
			} else {
				Integer uid = (Integer) dualHashBidiMap.get(auth);
				if (uid == null) {
					serviceResult.setErrorCode(219204512);// 验证码对应的id不存在
					logger.error("[ERR219204512] 验证码对应的id不存在");
					return serviceResult;
				}
				serviceResult.setData(uid);
				serviceResult.setErrorCode(0);
				logger.info("[INF219146647] 查询当前登录的用户 Id成功");
			}
			return serviceResult;
		} catch (Exception e) {
			TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
			serviceResult.setErrorCode(219311142);// 查询当前登录的用户 Id失败
			logger.error("[ERR219311142] 查询当前登录的用户 Id失败" + e.getMessage());
			return serviceResult;
		}

	}

}
